package com.aepryus.loom;

import java.util.*;
import java.sql.*;

class Pool {
	private String dbURL;
	private String username;
	private String password;

	private Stack<Connection> exclusive;
	private Map<Thread,Connection> threads;
	private List<Connection> shared;

	private int n;
	private int i=0;

	public Pool (String dbClass,String dbURL,String username,String password,int n) throws ClassNotFoundException,SQLException  {
		this.dbURL = dbURL;
		this.username = username;
		this.password = password;
		this.n = n;

		exclusive = new Stack<Connection>();
		threads = new HashMap<Thread,Connection>();
		shared = new Vector<Connection>();

		Class.forName(dbClass);
		for (int i=0;i<n;i++)
			addShared();
	}

	private Connection newConnection () throws SQLException {
		return DriverManager.getConnection(dbURL,username,password);
	}
	private void addShared () throws SQLException {
		shared.add(newConnection());
	}
	private void addExclusive () throws SQLException {
		Connection connection = newConnection();
		connection.setAutoCommit(false);
		exclusive.push(connection);
	}

	public synchronized Connection shared () {
		i = (i+1)%n;
		return shared.get(i);
	}
	public synchronized Connection exclusive () throws SQLException {
		Connection connection = threads.get(Thread.currentThread());

		if (connection == null) {
			if (exclusive.size() == 0)
				addExclusive();
			connection = exclusive.pop();
			threads.put(Thread.currentThread(),connection);
		}

		return connection;
	}
	public synchronized void release () {
		Connection connection = threads.get(Thread.currentThread());

		if (connection == null)
			throw new RuntimeException("Null connection attempting to be checked in.");

		exclusive.push(connection);
		threads.remove(Thread.currentThread());
	}

	public synchronized void refresh () throws SQLException {
		threads.remove(Thread.currentThread());
		addExclusive();
	}
	public synchronized void refresh (Connection connection) throws SQLException {
		shared.remove(connection);
		addShared();
	}
	public synchronized void close () throws SQLException {
		for (Connection connection : shared)
			connection.close();
		for (Thread thread : threads.keySet()) {
			Connection connection = threads.get(thread);
			connection.close();
		}
	}

// Object ======================================================================
	protected void finalize () throws Throwable {
		super.finalize();
		close();
	}
}

